package com.chzc.goods.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chzc.exception.OrderException;
import com.chzc.goods.mapper.GoodsMapper;
import com.chzc.goods.mapper.OrderInfoMapper;
import com.chzc.goods.req.OrderREQ;
import com.chzc.goods.service.IGoodsService;
import com.chzc.goods.service.IOrderInfoService;
import com.chzc.goods.service.RedisService;
import com.chzc.mq.GoodsOrderMQ;
import com.chzc.po.Goods;
import com.chzc.po.OrderInfo;
import com.chzc.server.DevilProducer;
import com.chzc.sys.service.IUserService;
import com.chzc.util.Result;
import com.chzc.util.enums.KillEnum;
import com.chzc.util.enums.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author CV大魔王
 * @since 2021-05-27
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    @Autowired
    private IGoodsService goodsService;

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IUserService userService;

    @Autowired
    private DevilProducer getProducer;


    @Override
    public Result placeAnOrder(String goodsId, String address) {
        // 当前登录的用户id
        String userId = StpUtil.getLoginIdAsString();
        // 查询商品详情
        Goods goods = goodsService.findById(goodsId);
        /* 三重流量拦截层+双重用户校验层 校验当前用户是否具有抢购资格*/
        Result result = checkWhetherItIsLegalV2(goodsId, userId, goods);
        if (!result.isFlag()) {
            return result;
        }

        // 生成唯一订单号
        String orderId = String.valueOf(IdWorker.getId());
        final String key = KillEnum.goods_booked_ + goodsId + userId;
        // 设置成功代表当前订单没有用户下单
        RLock lock = redissonClient.getLock(key);

        try {
            // 可重入锁
            boolean cacheRes = lock.tryLock(30, 10, TimeUnit.SECONDS);
            // 如果加锁成功，则进行业务逻辑。如果加锁失败代表正在进行下单，我们告诉用户已经下单完毕
            if (cacheRes) {

                // 封装发送消息的对象
                GoodsOrderMQ orderMQ = new GoodsOrderMQ();
                System.err.println("orderId:" + orderId);
                orderMQ.setOrderId(orderId);
                orderMQ.setAddress(address);
                goods.setGoodsDetailMd("");
                goods.setGoodsDetail("");
                orderMQ.setGoods(goods);
                orderMQ.setUserId(userId);
                orderMQ.setOrderId(orderId);

                // 消息内容
                String message = JSON.toJSONString(orderMQ);
                // 发送消息
                getProducer.sendMag("GOODS_ORDER", message);
            } else {
                return new Result(false, StatusCode.KILL_FULL_FAIL.getCode(), StatusCode.KILL_FULL_FAIL.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 强制释放锁
            lock.unlock();
        }
        return Result.buildSuccess();
    }


    @Override
    public IPage<OrderInfo> getMeOrder(OrderREQ req) {
        String userId = StpUtil.getLoginIdAsString();
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        if (req.getStatus() != null) {
            wrapper.eq("status", req.getStatus());
        }
        if (req.getGoodName() != null && StringUtils.isNotBlank(req.getGoodName())) {
            wrapper.like("good_name", req.getGoodName());
        }
        return baseMapper.selectPage(req.getPage(), wrapper);
    }

    /**
     * 付款，获取订单状态
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public Result payment(String orderId) {
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        if (orderInfo == null) {
            throw new OrderException("支付超时，您的订单已关闭");
        }
        // 设置成功代表当前订单没有用户下单
        RLock lock = redissonClient.getLock("ORDER_PAY_" + orderId);
        boolean cacheRes = false;
        try {
            cacheRes = lock.tryLock(30, 10, TimeUnit.SECONDS);
            if (cacheRes) {
                if (orderInfo.getStatus() != 0) {
                    throw new OrderException("请勿重复支付");
                }
                orderInfo.setStatus(1);
                baseMapper.updateById(orderInfo);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new OrderException("订单中，请勿重复支付");
        } finally {
            // 强制释放锁
            lock.unlock();
        }
        return new Result(true, 20000, "支付成功");
    }

    @Override
    public IPage<OrderInfo> queryPageList(OrderREQ req) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(req.getGoodName())) {
            wrapper.eq("good_name", req.getGoodName());
        }
        if (req.getStatus() != null) {
            wrapper.eq("status", req.getStatus());
        }
        return baseMapper.selectPage(req.getPage(),wrapper);
    }

    @Override
    public Result delete(String id) {
        baseMapper.deleteById(id);
        return Result.deleteSuccess();
    }

    @Override
    public Result ship(String id) {
        OrderInfo orderInfo = baseMapper.selectById(id);
        orderInfo.setStatus(2);
        baseMapper.updateById(orderInfo);
        return Result.buildSuccess();
    }

    /**
     * 判断当前用户是否具有抢购资格
     *
     * @param goodsId 商品id
     * @param userId  用户id
     * @param goods   商品信息
     */
    private Result checkWhetherItIsLegalV2(String goodsId, String userId, Goods goods) {
        try {
            /* =========================== 流量冲击拦截（上）-秒杀是否在时间段内是否有该商品-第一、二层流量冲击拦截 =========================== */
            // 向Redis查询秒杀是否开始
            String isStart = String.valueOf(redisService.get(KillEnum.goods_id_start_ + goodsId));
            // 如果为空代表秒杀结束或者没有此商品
            if (StringUtils.isBlank(isStart)) {
                return new Result(false, StatusCode.KILL_END_DATE_FAIL.getCode(), StatusCode.KILL_END_DATE_FAIL.getMessage());
            }

            if (isStart.contains("_")) {
                // 是否开始 0未开始 1正在进行
                long isStartInt = Long.parseLong(isStart.split("_")[0].trim());
                // 开始时间
                long startTime = Long.parseLong(isStart.split("_")[1].trim());
                if (isStartInt == 0) {
                    if (startTime > System.currentTimeMillis()) {
                        return new Result(false, StatusCode.KILL_START_DATE_FAIL.getCode(), StatusCode.KILL_START_DATE_FAIL.getMessage());
                    } else {
                        //代表秒杀已经开始
                        redisService.set(KillEnum.goods_id_start_ + goodsId, 1 + "");
                    }
                } else {
                    return Result.buildError();
                }
            } else {
                // 理论上秒杀已经开始，如果不为1代表出现了其他错误，不符合我们设置的逻辑
                if (Integer.parseInt(isStart) != 1) {
                    return Result.buildError();
                }
            }


            /* =========================== 流量冲击拦截（下）-秒杀商品是否达到最大访问限制-第三层流量冲击拦截 =========================== */
            // 当前商品最大下单限制
            int countMax = (Integer) redisService.get(KillEnum.goods_count_ + goods.getId());
            // 当前商品已下单人数
            int accessNumInt = (Integer) redisService.get(KillEnum.goods_access_ + goods.getId());

            if (accessNumInt >= countMax) {
                // 返回库存不足
                return new Result(false, StatusCode.KILL_FAIL.getCode(), StatusCode.KILL_FAIL.getMessage());
            } else {
                // 原子加
                redisService.incr(KillEnum.goods_access_ + goods.getId(), 1);
            }

            /* ===========================  信息校验层（上）- redis校验当前用户是否已经抢购过该商品 ===========================  */
            RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(KillEnum.goods_bloom_filter_ + goodsId);

            // 判断用户是否在布隆过滤器中
            boolean contains = bloomFilter.contains(userId);
            if (contains) {
                return new Result(false, StatusCode.KILL_FULL_FAIL.getCode(), StatusCode.KILL_FULL_FAIL.getMessage());
            } else {
                // 将当前用户加入到布隆过滤器
                bloomFilter.add(userId);
            }


            /* ===========================  信息校验层（下）-redis校验库存是否充足 ===========================  */
            int stock = (Integer) redisService.get(KillEnum.goods_stock_ + goods.getId());
            // 库存不足
            if (stock <= 0) {
                return new Result(false, StatusCode.KILL_FAIL.getCode(), StatusCode.KILL_FAIL.getMessage());
            } else {
                // 库存-1
                redisService.decr(KillEnum.goods_stock_ + goods.getId(), 1);
            }
            return Result.buildSuccess();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 秒杀后生成的订单
     *
     * @param goods   秒杀商品信息
     * @param address 收货地址
     * @param userId  用户id
     * @param orderId 订单编号
     * @param score   用户抢购名次
     */
    public void commonRecordKillSuccessInfo(Goods goods, String address, String userId, String orderId, int score) {
        OrderInfo orderInfo = new OrderInfo();

        // 商品秒杀价格
        orderInfo.setGoodsOldPrice(goods.getSeckillPrice());

        // 商品秒杀+折扣价格
        if (score <= 100) {
            orderInfo.setGoodsDiscount("1折");
            orderInfo.setGoodsPrice(goods.getSeckillPrice().multiply(BigDecimal.valueOf(0.1)));
        } else if (score <= 500) {
            orderInfo.setGoodsDiscount("5折");
            orderInfo.setGoodsPrice(goods.getSeckillPrice().multiply(BigDecimal.valueOf(0.5)));
        } else if (score <= 1000) {
            orderInfo.setGoodsDiscount("8折");
            orderInfo.setGoodsPrice(goods.getSeckillPrice().multiply(BigDecimal.valueOf(0.8)));
        } else {
            orderInfo.setGoodsDiscount("原价");
            orderInfo.setGoodsPrice(goods.getSeckillPrice());
        }

        orderInfo.setId(orderId);
        orderInfo.setUserId(userId);
        orderInfo.setGoodsId(goods.getId());
        orderInfo.setDeliveryAddrId(address);
        orderInfo.setGoodName(goods.getGoodsTitle());
        orderInfo.setGoodsCount(1);

        orderInfo.setOrderChannel(1);
        orderInfo.setStatus(0);
        orderInfo.setGoodsImg(goods.getGoodsImg());
        orderInfo.setCreateDate(new Date());
        baseMapper.insert(orderInfo);
    }
}
